package com.zhaogang.transactionManagerDemo.service.impl;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Savepoint;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.zhaogang.transactionManagerDemo.entity.SystemLog;
import com.zhaogang.transactionManagerDemo.service.AccountTransactionService;
import com.zhaogang.transactionManagerDemo.util.DBUtils;

@Service("AccountTransactionServiceJdbcImpl")
public class AccountTransactionServiceJdbcImpl implements AccountTransactionService {
	
	@Autowired
	private DataSource ds;
	
	private static Logger logger = LoggerFactory.getLogger(AccountTransactionServiceJdbcImpl.class);
	
	@Override
	public int updateBalanceByAccountNo(String accountNo, BigDecimal amount) {
		return 0;
	}

	@Override
	public void transferSimple(String fromAccountNo, String toAccountNo, BigDecimal amount) {
		Connection conn = null;
		PreparedStatement ps = null;
		PreparedStatement ps2 = null;
		int cnt = 0;
		try {
			conn = ds.getConnection();
			conn.setAutoCommit(false);
			
			//step1
			ps = conn.prepareStatement("update account set balance = balance + ? where account_no=?");
			ps.setBigDecimal(1, amount);
			ps.setString(2, toAccountNo);
			cnt = ps.executeUpdate();
			if (cnt == 0) {
				throw new RuntimeException();
			}
			
			//step2
			ps2 = conn.prepareStatement("update account set balance = balance - ? where account_no=?");
			ps2.setBigDecimal(1, amount);
			ps2.setString(2, fromAccountNo);
			cnt = ps2.executeUpdate();
			if (cnt == 0) {
				throw new RuntimeException();
			}
			conn.commit();
		} catch (Exception e) {
			try {
				conn.rollback();
			} catch (SQLException e1) {
				logger.info(e1.getMessage(),e1);
			}
			logger.info(e.getMessage(),e);
		}finally {
			DBUtils.closeConn(conn, ps, null);
			DBUtils.closeConn(conn, ps2, null);
		}		
	}

	@Override
	public void transferSimpleNoTrans(String fromAccountNo, String toAccountNo, BigDecimal amount) {

	}

	@Override
	public void transfer(String fromAccountNo, String toAccountNo, BigDecimal amount) {
		Connection conn = null;
		Connection conn2 = null;
		PreparedStatement ps = null;
		PreparedStatement ps2 = null;
		PreparedStatement ps3 = null;
		PreparedStatement ps4 = null;
		int cnt = 0;
		try {
			conn = ds.getConnection();
			conn.setAutoCommit(false);

			//step1
			ps = conn.prepareStatement("update account set balance = balance + ? where account_no=?");
			ps.setBigDecimal(1, amount);
			ps.setString(2, toAccountNo);
			cnt = ps.executeUpdate();
			if (cnt == 0) {
				throw new RuntimeException();
			}
			
			Savepoint savepoint = conn.setSavepoint("step1");
			//step2	
			conn2 = ds.getConnection();
			ps3 = conn2.prepareStatement("insert into system_log(topic, table_name,json_prev, json, last_modified_time) values (?, ?, ?, ?, ?)");
			ps3.setString(1, "转账更新转入账户");
			ps3.setString(2, "Account");
			ps3.setString(3, "12345678901234567890");
			ps3.setString(4, "1234567890");
			ps3.setDate(5, new java.sql.Date(new java.util.Date().getTime()));
			cnt = ps3.executeUpdate();
			if (cnt == 0) {
				throw new RuntimeException();
			}

			conn.releaseSavepoint(savepoint);
			//step3			
			ps2 = conn.prepareStatement("update account set balance = balance - ? where account_no=?");
			ps2.setBigDecimal(1, amount);
			ps2.setString(2, fromAccountNo);
			cnt = ps2.executeUpdate();
			if (cnt == 0) {
				throw new RuntimeException();
			}
			
			//step4	
			savepoint = conn.setSavepoint("step3");
			ps4 = conn2.prepareStatement("insert into system_log(topic, table_name,json_prev, json, last_modified_time) values (?, ?, ?, ?, ?)");
			ps4.setString(1, "转账更新转出账户");
			ps4.setString(2, "Account");
			ps4.setString(3, "1234567890123456789012345678901234567890");
			ps4.setString(4, "1234567890");
			ps4.setDate(5, new java.sql.Date(new java.util.Date().getTime()));
			cnt = ps4.executeUpdate();
			if (cnt == 0) {
				throw new RuntimeException();
			}
			
			conn.releaseSavepoint(savepoint);			
			
			conn.commit();
		} catch (SQLException e) {
			try {
				conn.rollback();
			} catch (SQLException e1) {
				logger.info(e1.getMessage(),e1);
			}
			logger.info(e.getMessage(),e);
		}finally {
			DBUtils.closeConn(conn, ps, null);
			DBUtils.closeConn(conn, ps2, null);
			DBUtils.closeConn(conn, ps3, null);
			DBUtils.closeConn(conn, ps4, null);
		}	
	}

	@Override
	public SystemLog addLog(String topic, String tableName, Object old, Object now) {
		return null;
	}

	@Override
	public void transferException(String fromAccountNo, String toAccountNo, BigDecimal amount) throws Exception {
		// TODO Auto-generated method stub
		
	}

}
